﻿using Roton.Memory;
using Roton.ZZT;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Roton.Wrapper.ZZT
{
    class ZZTMemoryWrapper : MemoryWrapper
    {
        public ZZTMemoryWrapper()
        {
            this.heap = new Heap();
            this.segment = new Segment(0x9610);

            this.elementOffset = 0x4AD4;
            this.elementSize = 0x00C3;
            this.thingOffset = 0x31CF;
            this.thingSize = 0x0021;

            this.segment.Write(0x0000, Properties.Resources.zztextra);
            this.segment.Write(this.elementOffset, Properties.Resources.zztelement);

            this.boardProperties = new BoardWrapperProperties();
            this.boardProperties.Width = 60 + 2;
            this.boardProperties.Height = 25 + 2;
            this.boardProperties.OffsetName = 0x2486;
            this.boardProperties.OffsetTiles = 0x24B9;
            this.boardProperties.OffsetMaxShots = 0x4567;
            this.boardProperties.OffsetDark = 0x4568;
            this.boardProperties.OffsetExits = 0x4569;
            this.boardProperties.OffsetRestartZap = 0x456D;
            this.boardProperties.OffsetEnter = 0x45A9;
            this.boardProperties.OffsetCamera = int.MinValue; // not in ZZT
            this.boardProperties.OffsetTimeLimit = 0x45AB;

            this.elementProperties = new ElementWrapperProperties();
            this.elementProperties.OffsetChar = 0x0000;
            this.elementProperties.OffsetColor = 0x0001;
            this.elementProperties.OffsetDestructible = 0x0002;
            this.elementProperties.OffsetPushable = 0x0003;
            this.elementProperties.OffsetAlwaysShown = 0x0004;
            this.elementProperties.OffsetEditorFloor = 0x0005;
            this.elementProperties.OffsetFloor = 0x0006;
            this.elementProperties.OffsetDrawCodeEnable = 0x0007;
            this.elementProperties.OffsetCycle = 0x000C;
            this.elementProperties.OffsetMenu = 0x0016;
            this.elementProperties.OffsetKey = 0x0018;
            this.elementProperties.OffsetName = 0x0019;
            this.elementProperties.OffsetEditorCategory = 0x002E;
            this.elementProperties.OffsetEditorP1 = 0x0043;
            this.elementProperties.OffsetEditorP2 = 0x0058;
            this.elementProperties.OffsetEditorP3 = 0x006D;
            this.elementProperties.OffsetEditorBoard = 0x0082;
            this.elementProperties.OffsetEditorStep = 0x0097;
            this.elementProperties.OffsetEditorCode = 0x00AC;
            this.elementProperties.OffsetPoints = 0x00C1;

            this.stateProperties = new StateWrapperProperties();
            this.stateProperties.OffsetAboutShown = 0x7A60;
            this.stateProperties.OffsetActIndex = 0x7406;
            this.stateProperties.OffsetAlertAmmo = 0x4AAB;
            this.stateProperties.OffsetAlertDark = 0x4AB1;
            this.stateProperties.OffsetAlertEnergy = 0x4AB5;
            this.stateProperties.OffsetAlertFake = 0x4AB3;
            this.stateProperties.OffsetAlertForest = 0x4AB2;
            this.stateProperties.OffsetAlertGem = 0x4AB4;
            this.stateProperties.OffsetAlertNoAmmo = 0x4AAC;
            this.stateProperties.OffsetAlertNoShoot = 0x4AAD;
            this.stateProperties.OffsetAlertNotDark = 0x4AB0;
            this.stateProperties.OffsetAlertNoTorch = 0x4AAF;
            this.stateProperties.OffsetAlertTorch = 0x4AAE;
            this.stateProperties.OffsetBoardCount = 0x45BE;
            this.stateProperties.OffsetBorderTile = 0x0072;
            this.stateProperties.OffsetBreakGameLoop = 0x4AC6;
            this.stateProperties.OffsetCancelScroll = 0x7B66;
            this.stateProperties.OffsetDefaultBoardName = 0x241E;
            this.stateProperties.OffsetDefaultSaveName = 0x23EA;
            this.stateProperties.OffsetDefaultWorldName = 0x2452;
            this.stateProperties.OffsetEdgeTile = 0x0074;
            this.stateProperties.OffsetEditorMode = 0x740C;
            this.stateProperties.OffsetGameCycle = 0x7404;
            this.stateProperties.OffsetGameOver = 0x7C8D;
            this.stateProperties.OffsetGamePaused = 0x7408;
            this.stateProperties.OffsetGameQuiet = 0x7C8C;
            this.stateProperties.OffsetGameSpeed = 0x4ACE;
            this.stateProperties.OffsetGameWaitTime = 0x7402;
            this.stateProperties.OffsetInit = 0x7B60;
            this.stateProperties.OffsetKeyArrow = 0x7C7E;
            this.stateProperties.OffsetKeyPressed = 0x7C70;
            this.stateProperties.OffsetKeyShift = 0x7C6C;
            this.stateProperties.OffsetKeyVector = 0x7C68;
            this.stateProperties.OffsetLineChars = 0x0098;
            this.stateProperties.OffsetMessage = 0x456E;
            this.stateProperties.OffsetOOPByte = 0x740E;
            this.stateProperties.OffsetOOPNumber = 0x7426;
            this.stateProperties.OffsetOOPWord = 0x7410;
            this.stateProperties.OffsetPlayerElement = 0x4AC8;
            this.stateProperties.OffsetQuitZZT = 0x4AC5;
            this.stateProperties.OffsetSoundBuffer = 0x7E90;
            this.stateProperties.OffsetSoundPlaying = 0x7F9A;
            this.stateProperties.OffsetSoundPriority = 0x7C8E;
            this.stateProperties.OffsetSoundTicks = 0x7E8F;
            this.stateProperties.OffsetStarChars = 0x0336;
            this.stateProperties.OffsetStartBoard = 0x4ACA;
            this.stateProperties.OffsetThingCount = 0x31CD;
            this.stateProperties.OffsetTransporterHChars = 0x0236;
            this.stateProperties.OffsetTransporterVChars = 0x0136;
            this.stateProperties.OffsetVector4 = 0x0062;
            this.stateProperties.OffsetVector8 = 0x0042;
            this.stateProperties.OffsetVisibleTileCount = 0x4ACC;
            this.stateProperties.OffsetWebChars = int.MinValue; // not in ZZT
            this.stateProperties.OffsetWorldFileName = 0x23B6;
            this.stateProperties.OffsetWorldLoaded = 0x7428;

            this.thingProperties = new ThingWrapperProperties();
            this.thingProperties.OffsetX = 0x0000;
            this.thingProperties.OffsetY = 0x0001;
            this.thingProperties.OffsetStepX = 0x0002;
            this.thingProperties.OffsetStepY = 0x0004;
            this.thingProperties.OffsetCycle = 0x0006;
            this.thingProperties.OffsetP1 = 0x0008;
            this.thingProperties.OffsetP2 = 0x0009;
            this.thingProperties.OffsetP3 = 0x000A;
            this.thingProperties.OffsetFollower = 0x000B;
            this.thingProperties.OffsetLeader = 0x000D;
            this.thingProperties.OffsetUnderID = 0x000F;
            this.thingProperties.OffsetUnderColor = 0x0010;
            this.thingProperties.OffsetPointer = 0x0011;
            this.thingProperties.OffsetInstruction = 0x0015;
            this.thingProperties.OffsetLength = 0x0017;
            
            this.worldProperties = new WorldWrapperProperties();
            this.worldProperties.LengthFlags = 0x0014;
            this.worldProperties.OffsetAmmo = 0x481E;
            this.worldProperties.OffsetGems = 0x4820;
            this.worldProperties.OffsetKeys = 0x4822;
            this.worldProperties.OffsetHealth = 0x4829;
            this.worldProperties.OffsetBoard = 0x482B;
            this.worldProperties.OffsetTorches = 0x482D;
            this.worldProperties.OffsetTorchCycles = 0x482F;
            this.worldProperties.OffsetEnergyCycles = 0x4831;
            this.worldProperties.OffsetScore = 0x4835;
            this.worldProperties.OffsetFlags = 0x4837;
            this.worldProperties.OffsetTimePassed = 0x491E;
            this.worldProperties.OffsetLocked = 0x4922;
            this.worldProperties.OffsetStones = int.MinValue; // not in ZZT

            this.board = new BoardWrapper(0, segment, boardProperties);
            this.state = new StateWrapper(0, segment, stateProperties);
            this.world = new WorldWrapper(0, segment, worldProperties);

            this.elementTypeList = new ElementType[]
            {
                ElementType.Empty,
                ElementType.BoardEdge,
                ElementType.Messenger,
                ElementType.Monitor,
                ElementType.Player,
                ElementType.Ammo,
                ElementType.Torch,
                ElementType.Gem,
                ElementType.Key,
                ElementType.Door,
                ElementType.Scroll,
                ElementType.Passage,
                ElementType.Duplicator,
                ElementType.Bomb,
                ElementType.Energizer,
                ElementType.Star,
                ElementType.Clockwise,
                ElementType.Counter,
                ElementType.Bullet,
                ElementType.Water,
                ElementType.Forest,
                ElementType.Solid,
                ElementType.Normal,
                ElementType.Breakable,
                ElementType.Boulder,
                ElementType.SliderNS,
                ElementType.SliderEW,
                ElementType.Fake,
                ElementType.Invisible,
                ElementType.BlinkWall,
                ElementType.Transporter,
                ElementType.Line,
                ElementType.Ricochet,
                ElementType.BlinkRayH,
                ElementType.Bear,
                ElementType.Ruffian,
                ElementType.Object,
                ElementType.Slime,
                ElementType.Shark,
                ElementType.SpinningGun,
                ElementType.Pusher,
                ElementType.Lion,
                ElementType.Tiger,
                ElementType.BlinkRayV,
                ElementType.Head,
                ElementType.Segment,
                ElementType.None,
                ElementType.BlueText,
                ElementType.GreenText,
                ElementType.CyanText,
                ElementType.RedText,
                ElementType.PurpleText,
                ElementType.BrownText,
                ElementType.BlackText
            };

            this.elementActCode = new ActDelegate[]
            {
                Act.Null,
                Act.Null,
                Act.Messenger,
                Act.Monitor,
                Act.Player,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Scroll,
                Act.Null,
                Act.Duplicator,
                Act.Bomb,
                Act.Null,
                Act.Star,
                Act.Clockwise,
                Act.Counter,
                Act.Bullet,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.BlinkWall,
                Act.Transporter,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Bear,
                Act.Ruffian,
                Act.Object,
                Act.Slime,
                Act.Shark,
                Act.SpinningGun,
                Act.Pusher,
                Act.Lion,
                Act.Tiger,
                Act.Null,
                Act.Head,
                Act.Segment,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null,
                Act.Null
            };

            this.elementDrawCode = new DrawDelegate[]
            {
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Duplicator,
                Draw.Bomb,
                Draw.Null,
                Draw.Star,
                Draw.Clockwise,
                Draw.Counter,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.BlinkWall,
                Draw.Transporter,
                Draw.Line,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Object,
                Draw.Null,
                Draw.Null,
                Draw.SpinningGun,
                Draw.Pusher,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null,
                Draw.Null
            };

            this.elementInteractCode = new InteractDelegate[]
            {
                Interact.Null,
                Interact.BoardEdge,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Ammo,
                Interact.Torch,
                Interact.Gem,
                Interact.Key,
                Interact.Door,
                Interact.Scroll,
                Interact.Passage,
                Interact.Null,
                Interact.Bomb,
                Interact.Energizer,
                Interact.EnemyGeneric,
                Interact.Null,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.Water,
                Interact.Forest,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.PushableGeneric,
                Interact.PushableGeneric,
                Interact.PushableGeneric,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Transporter,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.EnemyGeneric,
                Interact.Object,
                Interact.Slime,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.EnemyGeneric,
                Interact.Null,
                Interact.EnemyGeneric,
                Interact.EnemyGeneric,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null,
                Interact.Null
            };
        }
    }
}
